/*
 moxl - Modular XML Library
 Copyright (c) 2007, Malcolm Sparks

 This program is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License
 as published by the Free Software Foundation; either version 2
 of the License, or (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */
package moxl.tokenizer;

import java.util.LinkedList;

public class WhitespaceFilteringTokenStream extends TokenStream
{
	@SuppressWarnings("PMD.LooseCoupling")
	private final LinkedList<Token> buffer = new LinkedList<Token>();

	private final Tokenizer tokenizer;

	public WhitespaceFilteringTokenStream(Tokenizer tokenizer)
	{
		super(tokenizer);
		this.tokenizer = tokenizer;
	}

	/**
	 * @param count
	 *            Note this is 1-based, a lookahead of 1 peeks the next token in the stream
	 * @return the nth token left in the stream, or null if token stream is exceeded.
	 * @throws TokenizerException
	 */
	@Override
	public Token lookahead(int count) throws TokenizerException
	{
		if (count < 1)
		{
			throw new IllegalArgumentException("Lookahead cannot be less than one.");
		}
		if ((count - 1) < buffer.size())
		{
			return (Token) buffer.get((count - 1));
		}
		else
		{
			for (int i = buffer.size(); i < count; i++)
			{
				Token next = null;
				next = getTokenizer().nextToken();
				if (next == null)
				{
					return null;
				}
				while (next.isWhitespace())
				{
					next = getTokenizer().nextToken();
					if (next == null)
					{
						return null;
					}
				}
				buffer.addLast(next);
			}
			return (Token) buffer.getLast();
		}
	}

	/**
	 * @return the next token, or null if no more tokens.
	 */
	@Override
	public Token read() throws TokenizerException
	{
		if (buffer.isEmpty())
		{
			Token nextToken = getTokenizer().nextToken();
			while (nextToken != null && nextToken.isWhitespace())
			{
				nextToken = getTokenizer().nextToken();
			}
			return nextToken;
		}
		else
		{
			return (Token) buffer.removeFirst();
		}
	}

	@Override
	public void pushback(Token token)
	{
		if (token == null)
		{
			throw new IllegalArgumentException("Cannot push a null token back onto the stream.");
		}
		buffer.addFirst(token);
	}

	@Override
	public void setMode(AbstractTokenizerState mode) throws TokenizerException
	{
		if (!buffer.isEmpty())
		{
			throw new TokenizerException("Cannot change mode of tokenizer when there are tokens already buffered.");
		}
		tokenizer.setMode(mode);
	}

}
